package androidtopc;

import java.io.*;
import java.net.*;
import java.util.Arrays;
import java.util.List;

import javax.imageio.*;

import java.awt.image.BufferedImage;

public class Client {
	private Socket socket;
	private DataOutputStream out;
	private DataInputStream in;

	// Maximum Buffer for android
	private final int BUFFER_SIZE = (int) Math.pow(2, 15);

	// Server Info
	private final int PORT_NO = 2004;
	private final String HOST_NAME = "localhost";

	// Image directory
	private final String HOME_DIR = "C:/dev/UROP/images/";
	private final String IMAGE_TYPE = "jpg";
	private final String IMAGE_EXTENSION = "." + IMAGE_TYPE;
	
	private long averageTime = 0;
	private long nPics = 0;

	Client() {
	}

	void run() {
		// Connect to the server
		connect();

		// Successful connect message
		receiveMessage();

		// Communicate with server, keep track of how long it takes to send
		int temp = 0;
		while (true) {
			sendMessage("Sending Image: " + temp);
			
			long deltaT = System.currentTimeMillis();
			
			sendImage(HOME_DIR + "test2" + IMAGE_EXTENSION, IMAGE_TYPE);
			receiveBoolean();
			
			deltaT = System.currentTimeMillis() - deltaT;
			averageTime = (averageTime * nPics + deltaT) / (nPics + 1);
			System.out.println(averageTime);
			nPics++;
			temp++;
		}
		/*System.out.println("Average Time to send picture & receive ACK: " + averageTime);
		closeConnection();*/
	}

	/**
	 * Connect to the server and get the input/output streams
	 */
	void connect() {
		try {
			// Connect to the server
			socket = new Socket(HOST_NAME, PORT_NO);

			System.out.println("Connected to " + HOST_NAME + " on port "
					+ PORT_NO);

			// Get Input and Output streams
			in = new DataInputStream(socket.getInputStream());
			out = new DataOutputStream(socket.getOutputStream());
			out.flush();
		} catch (UnknownHostException unknownHost) {
			System.err.println("Unknown host, could not connect");
			System.exit(1);
		} catch (IOException ioException) {
			ioException.printStackTrace();
			System.exit(1);
		}
	}

	/**
	 * Close the connection with the server
	 */
	void closeConnection() {
		try {
			System.out.println("Closing connection");
			in.close();
			out.close();
			socket.close();
		} catch (IOException ioException) {
			ioException.printStackTrace();
		}
	}

	/**
	 * Send a message to the server
	 * 
	 * @param msg
	 *            message to send to server
	 */
	void sendMessage(String msg) {
		try {
			out.writeUTF(msg);
			out.flush();
			System.out.println("client> " + msg);
		} catch (IOException ioException) {
			System.err.println("Sending message error: "
					+ ioException.getMessage());
		}
	}

	/**
	 * Receive a message from the server and print it to the command line
	 */
	void receiveMessage() {
		try {
			String message = (String) in.readUTF();
			System.out.println("server> " + message);
		} catch (IOException ioException) {
			System.err.println("Receive message error: " + ioException.getMessage());
		}
	}

	/**
	 * Receive a boolean from the server and print it to the console
	 */
	void receiveBoolean() {
		try {
			boolean message = in.readBoolean();
			System.out.println("server> " + message);
		} catch (IOException ioException) {
			System.err.println("Receive message error: " + ioException.getMessage());
		}
	}

	/**
	 * Convert an image to a byte array.
	 * 
	 * @param filePath file path to image to convert to byte array
	 * @param imageType type of image (file extension)
	 * @return image converted to byte array
	 */
	byte[] imageToByte(final String filePath, final String imageType) {
		try {
			// Read Image
			BufferedImage bimg = ImageIO.read(new File(filePath));

			// Convert and add to byte stream
			ByteArrayOutputStream baos = new ByteArrayOutputStream();
			ImageIO.write(bimg, imageType, baos);
			baos.flush();

			// Store in byte array
			byte[] imageInByte = baos.toByteArray();
			baos.close();

			return imageInByte;
		} catch (IOException e) {
			System.out.println(e.getMessage());
			return null;
		}
	}

	void sleep(int ms) {
		try {
			Thread.sleep(ms);
		} catch (InterruptedException e) {
		}
	}

	/**
	 * Send the image to the server
	 * @param filePath	file path of the image to send
	 * @param imageType	type (file extension) of image to send
	 */
	void sendImage(String filePath, String imageType) {
		try {
			// Convert buffered image to byte array
			byte[] byteImage = imageToByte(filePath, imageType);
			// Send Header info, incl. image size
			out.writeInt(byteImage.length);

			// Get number of streams that are equal to buffer size
			int numBuffers = byteImage.length / BUFFER_SIZE;
			// Break up output into buffers and transmit
			for (int i = 0; i < numBuffers * BUFFER_SIZE; i += BUFFER_SIZE) {
				byte[] buffer = Arrays.copyOfRange(byteImage, i, i
						+ BUFFER_SIZE);
				out.write(buffer);
				out.flush();
				sleep(100);
			}
			
			// Send the end of the image array
			byte[] leftOverStream = Arrays.copyOfRange(byteImage, numBuffers
					* BUFFER_SIZE, byteImage.length);
			// Send image
			out.write(leftOverStream);
			out.flush();
		} catch (IOException e) {
			System.err.println("Sending image error: " + e.getMessage());
		}
	}

	public static void main(String args[]) {
		//for (int i = 1; i <= 2; i++) {
			Client client = new Client();
			client.run();
		//}
	}
}